package com.develop.wechatpay.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.develop.wechatpay.domain.WechatPayModel;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.HttpHost;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.junit.After;

import java.io.*;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.PrivateKey;

public class WeChatPayUtil {

    private static final String WeChatPay_IP = "https://api.mch.weixin.qq.com";
    private static final String WeChatPay_AddOrder_Url = "/v3/pay/transactions/jsapi";
    private static final String WeChatPay_QueryOrderByOut_Url = "/v3/pay/transactions/out-trade-no/";
    private static final String WeChatPay_QueryOrderById_Url = "/v3/pay/transactions/id/";
    private static final String WeChatPay_CloseOrderByOut_Url = "/v3/pay/transactions/out-trade-no/";
    private static final String WeChatPay_TradeBillDownFile_Url = "/v3/bill/tradebill";
    private static final String WeChatPay_FundFlowBillDownFile_Url = "/v3/bill/fundflowbill";

    public static void checkParam(WechatPayModel wechatPayModel, String priKeyPath, String merchantId, String appid,
                                  String merchantSerialNumber, String apiV3Key, String notify_url) throws Exception {
        if (StrUtil.isBlank(priKeyPath)) {
            throw new Exception("商户私钥地址必填");
        }
        if (StrUtil.isBlank(merchantId)) {
            throw new Exception("商户号必填");
        }
        if (StrUtil.isBlank(appid)) {
            throw new Exception("公众号Id必填");
        }
        if (StrUtil.isBlank(merchantSerialNumber)) {
            throw new Exception("商户证书序列号必填");
        }
        if (StrUtil.isBlank(apiV3Key)) {
            throw new Exception("API V3密钥必填");
        }
        if (StrUtil.isBlank(notify_url)) {//【通知地址】 异步接收微信支付结果通知的回调地址，通知URL必须为外网可访问的URL，不能携带参数。 公网域名必须为HTTPS，如果是走专线接入，使用专线NAT IP或者私有回调域名可使用HTTP
            throw new Exception("notify_url接收微信支付结果通知的回调地址必填");
        }
        boolean file = FileUtil.isFile(priKeyPath);
        if (!file) {
            throw new Exception("商户私钥地址不存在");
        }
        wechatPayModel.setMchid(merchantId);
        wechatPayModel.setAppid(appid);
        wechatPayModel.setNotify_url(notify_url);
    }

    public static Verifier GetVerifier(String priKeyPath, String merchantId, String merchantSerialNumber, String apiV3Key) throws IOException, HttpCodeException, GeneralSecurityException, NotFoundException {
        //方法1
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(priKeyPath));
        // 获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();
        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId,
                        new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),
                apiV3Key.getBytes(StandardCharsets.UTF_8));
        // 从证书管理器中获取verifier
        return certificatesManager.getVerifier(merchantId);
    }

    public static CloseableHttpClient GetWeChatPayHttpClient(String priKeyPath, String merchantId, String merchantSerialNumber, String apiV3Key) throws Exception {
        HttpHost proxy = null;
        //方法1
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(priKeyPath));
        // 获取证书管理器实例
        CertificatesManager certificatesManager = CertificatesManager.getInstance();
        // 添加代理服务器
        certificatesManager.setProxy(proxy);
        // 向证书管理器增加需要自动更新平台证书的商户信息
        certificatesManager.putMerchant(merchantId, new WechatPay2Credentials(merchantId,
                        new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),
                apiV3Key.getBytes(StandardCharsets.UTF_8));
        // 从证书管理器中获取verifier
        Verifier verifier = certificatesManager.getVerifier(merchantId);
        // 构造httpclient
        CloseableHttpClient httpClient = WechatPayHttpClientBuilder.create()
                .withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier))
                .build();
        return httpClient;
    }

    public static JSONObject jsapiAddOrder(CloseableHttpClient httpClient, WechatPayModel wechatPayModel) throws IOException {
        HttpPost httpPost = new HttpPost(WeChatPay_IP + WeChatPay_AddOrder_Url);
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
        httpPost.setEntity(new StringEntity(JSONObject.toJSONString(wechatPayModel), "UTF-8"));
        CloseableHttpResponse response = httpClient.execute(httpPost);
        String bodyAsString = EntityUtils.toString(response.getEntity());
        JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
        return jsonObject;
    }

    public static JSONObject queryOrderByOutRradeNo(CloseableHttpClient httpClient, String outRradeNo, String merchantId) throws IOException, URISyntaxException {
        String url = WeChatPay_IP + WeChatPay_QueryOrderByOut_Url + outRradeNo + "?mchid=" + merchantId;
        URIBuilder uriBuilder = new URIBuilder(url);
        HttpGet httpGet = new HttpGet(uriBuilder.build());
        httpGet.addHeader("Accept", "application/json");
        CloseableHttpResponse response = httpClient.execute(httpGet);
        String bodyAsString = EntityUtils.toString(response.getEntity());
        JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
        return jsonObject;
    }

    public static JSONObject queryOrderByTransactionId(CloseableHttpClient httpClient, String transactionId, String merchantId) throws IOException, URISyntaxException {
        String url = WeChatPay_IP + WeChatPay_QueryOrderById_Url + transactionId + "?mchid=" + merchantId;
        URIBuilder uriBuilder = new URIBuilder(url);
        HttpGet httpGet = new HttpGet(uriBuilder.build());
        httpGet.addHeader("Accept", "application/json");
        CloseableHttpResponse response = httpClient.execute(httpGet);
        String bodyAsString = EntityUtils.toString(response.getEntity());
        JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
        return jsonObject;
    }

    public static JSONObject closeOrderByOutRradeNo(CloseableHttpClient httpClient, String outRradeNo, String merchantId) throws IOException, URISyntaxException {
        HttpPost httpPost = new HttpPost(WeChatPay_IP + WeChatPay_CloseOrderByOut_Url + outRradeNo + "/close");
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
        JSONObject jsonObjectParam = new JSONObject();
        jsonObjectParam.put("mchid", merchantId);
        httpPost.setEntity(new StringEntity(jsonObjectParam.toJSONString(), "UTF-8"));
        CloseableHttpResponse response = httpClient.execute(httpPost);
        return queryOrderByOutRradeNo(httpClient, outRradeNo, merchantId);
    }

    public static JSONObject getTradeBillFile(CloseableHttpClient httpClient, String bill_date, String bill_type, String tar_type) throws URISyntaxException, IOException {
        if (StrUtil.isBlank(bill_type)) {
            bill_type = "ALL";
        }
        if (StrUtil.isBlank(tar_type)) {
            tar_type = "GZIP";
        }
        String url = WeChatPay_IP + WeChatPay_TradeBillDownFile_Url + "?bill_date=" + bill_date + "&bill_type=" + bill_type + "&tar_type=" + tar_type;
        URIBuilder uriBuilder = new URIBuilder(url);
        HttpGet httpGet = new HttpGet(uriBuilder.build());
        httpGet.addHeader("Accept", "application/json");
        CloseableHttpResponse response = httpClient.execute(httpGet);
        String bodyAsString = EntityUtils.toString(response.getEntity());
        JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
        return jsonObject;
    }

    public static JSONObject getFundFlowBillFile(CloseableHttpClient httpClient, String bill_date, String account_type, String tar_type) throws URISyntaxException, IOException {
        if (StrUtil.isBlank(account_type)) {
            account_type = "ALL";
        }
        if (StrUtil.isBlank(tar_type)) {
            tar_type = "GZIP";
        }
        String url = WeChatPay_IP + WeChatPay_FundFlowBillDownFile_Url + "?bill_date=" + bill_date + "&account_type=" + account_type + "&tar_type=" + tar_type;
        URIBuilder uriBuilder = new URIBuilder(url);
        HttpGet httpGet = new HttpGet(uriBuilder.build());
        httpGet.addHeader("Accept", "application/json");
        CloseableHttpResponse response = httpClient.execute(httpGet);
        String bodyAsString = EntityUtils.toString(response.getEntity());
        JSONObject jsonObject = JSONObject.parseObject(bodyAsString);
        return jsonObject;
    }
}
